home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / passwd+ / test.y < prev    next >
Encoding:
Lex Description  |  1992-06-10  |  12.9 KB  |  587 lines

  1. %{
  2. /*
  3.  * this file implements the grammar for the password tests
  4.  * the escapes are handled in the caller
  5.  */
  6.  
  7. #include "passwd.h"
  8.  
  9. %}
  10.  
  11. /*
  12.  * the lexer returns both numbers and strings
  13.  */
  14. %union {
  15.     char *cval;        /* something parsed as a string */
  16.     int ival;        /* something parsed as a number */
  17. }
  18.  
  19. /*
  20.  * tokens returned by the lexical analyzer yylex()
  21.  */
  22. %token <ival> AND        /* number: (logical) disjunction */
  23. %token <ival> DIV        /* number: (arithmetic) division */
  24. %token <ival> EOL        /* number: no more input */
  25. %token <ival> EQ        /* number: (relational) equals */
  26. %token <cval> FILENAME        /* string: a file */
  27. %token <ival> GE        /* number: (relational) greater than or equal */
  28. %token <ival> GT        /* number: (relational) greater than */
  29. %token <ival> LE        /* number: (relational) less than or equal */
  30. %token <ival> LPAR        /* number: begin grouping */
  31. %token <ival> LT        /* number: (relational) less than */
  32. %token <ival> MINUS        /* number: (arithmetic) subtraction, negation */
  33. %token <ival> MOD        /* number: (arithmetic) remaindering */
  34. %token <ival> NE        /* number: (relational) not equal */
  35. %token <ival> NOT        /* number: (logical) negation */
  36. %token <ival> NUMBER        /* number: number or value of a variable */
  37. %token <ival> OR        /* number: (logical) conjunction */
  38. %token <ival> PATEQ        /* number: (pattern) match */
  39. %token <ival> PATNE        /* number: (pattern) no match */
  40. %token <cval> STRING        /* string: compare to a pattern */
  41. %token <ival> PLUS        /* number: (arithmetic) addition */
  42. %token <cval> PROGRAM        /* string: a program */
  43. %token <ival> RPAR        /* number: end grouping */
  44. %token <ival> TIMES        /* number: (arithmetic) multiplication */
  45. %token <ival> UNK         /* number: unknown token */
  46.  
  47. /*
  48.  * productions analyzed by the parser
  49.  */
  50. %type <ival> number        /* number: something arithmetic */
  51. %type <ival> prim        /* number: 1 if relation is satisfied */
  52. %type <ival> stat        /* number: test with EOL tacked on */
  53. %type <ival> string        /* number: 1 if string relation true */
  54. %type <ival> test        /* number: 1 if test passed so far */
  55.  
  56. /*
  57.  * expression operators
  58.  * these must be on the same line since they are of equal precedence
  59.  */
  60. %right NOT            /* negation of tests */
  61. %left OR AND            /* grouping of tests */
  62. %left TIMES DIV MOD        /* usual arithmetic ordering */
  63. %left PLUS MINUS
  64. %nonassoc LT GT NE EQ GE LE    /* relational operators don't associate */
  65.  
  66. %{
  67.  
  68. /*
  69.  * variables
  70.  */
  71. static int retval;        /* 1 if test passed, 0 if not */
  72. static char *lptr;        /* used to walk input string */
  73. static int ateol;        /* 1 when you hit end of string */
  74.  
  75. %}
  76.  
  77. /*
  78.  * start analysis at state stat
  79.  */
  80. %start stat
  81.  
  82. %%
  83. stat        : test EOL
  84.             { retval = $1 ; }
  85.         | error EOL
  86.             { retval = 1; }
  87.         | EOL
  88.             { retval = 0; }
  89.         ;
  90.  
  91. test        : LPAR test RPAR
  92.             { $$ = $2 ; }
  93.         | test AND test
  94.             { $$ = $1 && $3 ; }
  95.         | test OR test
  96.             { $$ = $1 || $3 ; }
  97.         | NOT test
  98.             { $$ = ! $2 ; }
  99.         | string
  100.             { $$ = $1 ; }
  101.         | prim
  102.             { $$ = $1 ; }
  103.         ;
  104.  
  105. string        : STRING EQ STRING
  106.             { $$ = (strcmp( $1 , $3 ) == 0);
  107.               (void) free( $1 ); (void) free( $3 );
  108.             }
  109.         | STRING NE STRING
  110.             { $$ = (strcmp( $1 , $3 ) != 0);
  111.               (void) free( $1 ); (void) free( $3 );
  112.             }
  113.         | STRING PATEQ STRING
  114.             { if (smatch( $3 )) YYERROR; $$ = match( $1 );
  115.               (void) free( $1 ); (void) free( $3 );
  116.             }
  117.         | STRING PATNE STRING
  118.             { if (smatch( $3 )) YYERROR; $$ = !match( $1 );
  119.               (void) free( $1 ); (void) free( $3 );
  120.             }
  121.         | STRING EQ FILENAME
  122.             { $$ = strfp(1, $1 , $3 , fopen, fclose);
  123.               (void) free( $1 ); (void) free( $3 );
  124.             }
  125.         | STRING NE FILENAME
  126.             { $$ = strfp(0, $1 , $3 , fopen, fclose);
  127.               (void) free( $1 ); (void) free( $3 );
  128.             }
  129.         | STRING PATEQ FILENAME
  130.             { $$ = patinfp(1, $1 , $3 , fopen, fclose);
  131.               (void) free( $1 ); (void) free( $3 );
  132.             }
  133.         | STRING PATNE FILENAME
  134.             { $$ = patinfp(0, $1 , $3 , fopen, fclose);
  135.               (void) free( $1 ); (void) free( $3 );
  136.             }
  137.         | STRING EQ PROGRAM
  138.             { $$ = strfp(1, $1 , $3 , popen, pclose);
  139.               (void) free( $1 ); (void) free( $3 );
  140.             }
  141.         | STRING NE PROGRAM
  142.             { $$ = strfp(0, $1 , $3 , popen, pclose);
  143.               (void) free( $1 ); (void) free( $3 );
  144.             }
  145.         | STRING PATEQ PROGRAM
  146.             { $$ = patinfp(1, $1 , $3 , popen, pclose);
  147.               (void) free( $1 ); (void) free( $3 );
  148.             }
  149.         | STRING PATNE PROGRAM
  150.             { $$ = patinfp(0, $1 , $3 , popen, pclose);
  151.               (void) free( $1 ); (void) free( $3 );
  152.             }
  153.         | FILENAME EQ STRING
  154.             { $$ = strfp(1, $3 , $1 , fopen, fclose);
  155.               (void) free( $1 ); (void) free( $3 );
  156.             }
  157.         | FILENAME NE STRING
  158.             { $$ = strfp(0, $3 , $1 , fopen, fclose);
  159.               (void) free( $1 ); (void) free( $3 );
  160.             }
  161.         | FILENAME PATEQ STRING
  162.             { $$ = patfp(1, $3 , $1 , fopen, fclose);
  163.               (void) free( $1 ); (void) free( $3 );
  164.             }
  165.         | FILENAME PATNE STRING
  166.             { $$ = patfp(0, $3 , $1 , fopen, fclose);
  167.               (void) free( $1 ); (void) free( $3 );
  168.             }
  169.         | PROGRAM EQ STRING
  170.             { $$ = strfp(1, $3 , $1 , popen, pclose);
  171.               (void) free( $1 ); (void) free( $3 );
  172.             }
  173.         | PROGRAM NE STRING
  174.             { $$ = strfp(0, $3 , $1 , popen, pclose);
  175.               (void) free( $1 ); (void) free( $3 );
  176.             }
  177.         | PROGRAM PATEQ STRING
  178.             { $$ = patfp(1, $3 , $1 , popen, pclose);
  179.               (void) free( $1 ); (void) free( $3 );
  180.             }
  181.         | PROGRAM PATNE STRING
  182.             { $$ = patfp(0, $3 , $1 , popen, pclose);
  183.               (void) free( $1 ); (void) free( $3 );
  184.             }
  185.         ;
  186.  
  187. prim        : number LT number
  188.             { $$ = $1 < $3 ; }
  189.         | number GT number
  190.             { $$ = $1 > $3 ; }
  191.         | number NE number
  192.             { $$ = $1 != $3 ; }
  193.         | number EQ number
  194.             { $$ = $1 == $3 ; }
  195.         | number GE number
  196.             { $$ = $1 >= $3 ; }
  197.         | number LE number
  198.             { $$ = $1 <= $3 ; }
  199.         ;
  200.  
  201. number        : LPAR number RPAR
  202.             { $$ = $2 ; }
  203.         | number PLUS number
  204.             { $$ = $1 + $3 ; }
  205.         | PLUS number        %prec TIMES
  206.             { $$ = $1 ; }
  207.         | number MINUS number
  208.             { $$ = $1 - $3 ; }
  209.         | MINUS number        %prec TIMES
  210.             { $$ = - $1 ; }
  211.         | number TIMES number
  212.             { $$ = $1 * $3 ; }
  213.         | number DIV number
  214.             { $$ = $1 / $3 ; }
  215.         | number MOD number
  216.             { $$ = $1 % $3 ; }
  217.         | NUMBER
  218.             { $$ = $1 ; }
  219.         ;
  220.  
  221. %%
  222.  
  223. /*
  224.  * this is the lexer -- it's pretty dumb
  225.  */
  226. yylex()
  227. {
  228.     static char parbuf[BUFSIZ];    /* used to save strings */
  229.     register int rval;        /* used for return values */
  230.     register char quo;        /* used to hold terminal quote mark */
  231.  
  232.     /*
  233.      * this is hit at the end of string
  234.      * we need to do it this way because the '\0' (EOL)
  235.      * token must be returned, so we have toi return
  236.      * another "end of input" token -- in other words,
  237.      * the end of input character is NOT the same as 
  238.      * the end of string (EOL) character
  239.  
  240.      */
  241.     if (ateol){
  242.         ateol = 0;
  243.         return(-1);    /* YACC's end of file character */
  244.     }
  245.  
  246.     /*
  247.      * eat leading white spaces; may have a backslash in front
  248.      * (since a tab separates the test field and the message
  249.      * field, if there is a tab in the test field it must be
  250.      * escaped)
  251.      */
  252.     while(*lptr)
  253.         if (isspace(*lptr))
  254.             lptr++;
  255.         else if (*lptr == '\\'){
  256.             if (isspace(lptr[1]))
  257.                 lptr += 2;
  258.             else
  259.                 break;
  260.         }
  261.         else
  262.             break;
  263.  
  264.     /*
  265.      * hit end of string character
  266.      * indicate there's nothing more with ateol
  267.      * (so next tile we return YACC's end of file)
  268.      * and return the EOL token
  269.      */
  270.     if (*lptr == '\0'){
  271.         ateol = 1;
  272.         return(EOL);
  273.     }
  274.  
  275.     /*
  276.      * number -- just return it
  277.      */
  278.     if (isdigit(*lptr)){
  279.         for(rval = 0; isdigit(*lptr); lptr++)
  280.             rval = rval * 10 + *lptr - '0';
  281.         yylval.ival = rval;
  282.         return(NUMBER);
  283.     }
  284.  
  285.     /*
  286.      * something else -- analyze it
  287.      */
  288.     switch(*lptr++){
  289.     case '@':        /* rest of line is comment */
  290.     case '\t':        /* rest of line is error message */
  291.     case '\n':        /* end of line */
  292.     case '\0':        /* end of line */
  293.         ateol = 1;
  294.         return(EOL);
  295.     case '(':        /* begin grouping */
  296.         return(LPAR);
  297.     case ')':        /* end grouping */
  298.         return(RPAR);
  299.     case '~':        /* negation */
  300.         return(NOT);
  301.     case '+':        /* add */
  302.         return(PLUS);
  303.     case '-':        /* subtract */
  304.         return(MINUS);
  305.     case '*':        /* multiply */
  306.         return(TIMES);
  307.     case '/':        /* divide */
  308.         return(DIV);
  309.     case '%':        /* remainder */
  310.         return(MOD);
  311.     case '&':        /* disjunction */
  312.         if (*lptr++ == '&')    /* && */
  313.             return(AND);
  314.         --lptr;            /* & */
  315.         return(AND);
  316.     case '|':        /* conjunction */
  317.         if (*lptr++ == '|')    /* || */
  318.             return(OR);
  319.         --lptr;            /* | */
  320.         return(OR);
  321.     case '>':        /* relation */
  322.         if (*lptr++ == '=')    /* >= */
  323.             return(GE);
  324.         --lptr;            /* > */
  325.         return(GT);
  326.     case '<':        /* relation */
  327.         if (*lptr++ == '=')    /* <= */
  328.             return(LE);
  329.         --lptr;            /* < */
  330.         return(LT);
  331.     case '!':        /* relation, logical negation */
  332.         if (*lptr++ == '=')    /* != */
  333.             return(NE);
  334.         --lptr;    
  335.         if (*lptr++ == '~')    /* !~ */
  336.             return(PATNE);
  337.         --lptr;            /* logical negation */
  338.         return(NOT);
  339.     case '=':
  340.         if (*lptr++ == '=')    /* == */
  341.             return(EQ);
  342.         --lptr;    
  343.         if (*lptr++ == '~')    /* =~ */
  344.             return(PATEQ);
  345.         --lptr;            /* = */
  346.         return(EQ);
  347.     case '\'':            /* pattern */
  348.     case '"':            /* pattern */
  349.     case '{':            /* program */
  350.     case '[':            /* file */
  351.         /*
  352.          * figure out what you're dealing with
  353.          */
  354.         if (lptr[-1] == '\'' || lptr[-1] == '"'){    /* pattern */
  355.             quo = lptr[-1];
  356.             rval = STRING;
  357.         }
  358.         else if (lptr[-1] == '{'){    /* program */
  359.             quo = '}';
  360.             rval = PROGRAM;
  361.         }
  362.         else{                /* file */
  363.             quo = ']';
  364.             rval = FILENAME;
  365.         }
  366.         /*
  367.          * collect the file or program or pattern
  368.          */
  369.         lptr = getcstring(lptr, parbuf, quo);
  370.         /*
  371.          * if no closing quote, warn but accept;
  372.          * if a closing quote, skip it
  373.          */
  374.         if (!*lptr)
  375.             yyerror("missing quote -- supplying it");
  376.         else
  377.             lptr++;
  378.         /*
  379.          * return the file or program as the value
  380.          */
  381.         yylval.cval = strsave(parbuf);
  382.         return(rval);
  383.     }
  384.  
  385.     /*
  386.      * unknown
  387.      */
  388.     return(UNK);
  389. }
  390.  
  391. /*
  392.  * report error on a pattern (malformed ...)
  393.  */
  394. paterr(msg)
  395. char *msg;        /* error message from pattern compiler/matcher */
  396. {
  397.     /*
  398.      * print the error message
  399.      */
  400.     LOG3(LG_SYNTAX, "%s at line %d (at \"%s\")", msg, linect, lptr-1);
  401. }
  402.  
  403. /*
  404.  * report system errors
  405.  */
  406. sysyyerror(s)
  407. char *s;        /* what screwed up */
  408. {
  409.     char buf[BUFSIZ];    /* buffer for error message */
  410.  
  411.     /*
  412.      * print the system error message if available,
  413.      * or the error number if not
  414.      */
  415.     if (errno < sys_nerr)
  416.         SPRINTF(buf, "line %d: %s: %s at \"%s\"",
  417.                     linect, s, sys_errlist[errno], lptr-1);
  418.     else
  419.         SPRINTF(buf, "line %d: %s: unknown error #%d at \"%s\"",
  420.                         linect, s, errno, lptr-1);
  421.     LOG0(LG_SYSTEM, buf);
  422. }
  423.  
  424. /*
  425.  * report grammar errors (yacc)
  426.  */
  427. yyerror(s)
  428. char *s;        /* how the parse screwed up */
  429. {
  430.     /*
  431.      * print the error message
  432.      */
  433.     LOG3(LG_SYNTAX, "%s at line %d (at \"%s\")", s, linect, lptr-1);
  434.  
  435.     /*
  436.      * signal end of test
  437.      */
  438.     ateol = 1;
  439. }
  440.  
  441. /*==================== DRIVER ====================*/
  442. /*
  443.  * this runs the test in "buf" on the password
  444.  * and returns 1 if it passes, 0 of not
  445.  */
  446. passtest(buf)
  447. char *buf;            /* the test */
  448. {
  449.     /*
  450.      * clear the end of line flag
  451.      */
  452.     ateol = 0;
  453.  
  454.     /*
  455.      * clobber any trailing newline
  456.      */
  457.     lptr = &buf[strlen(buf)-1];
  458.     if (*lptr == '\n')
  459.         *lptr = '\0';
  460.     else
  461.         lptr[2] = '\0';
  462.  
  463.     /*
  464.      * set up the pointer to the input
  465.      * for yylex, the lexical analyzer
  466.      */
  467.     lptr = buf;
  468.  
  469.     /*
  470.      * parse the date and process the result
  471.      */
  472.     if (yyparse()){
  473. #ifdef DEBUG
  474.         PRINTF("illegal test for password\n");
  475. #endif
  476.         return(0);
  477.     }
  478.  
  479.     /*
  480.      * test is syntactically and semantically correct
  481.      * and return the result
  482.      */
  483. #ifdef DEBUG
  484.     PRINTF("password \"%s\" %s this test\n",
  485.             password, retval ? "passes" : "does not pass");
  486. #endif
  487.     return(retval);
  488. }
  489.     
  490.  
  491.  
  492.  
  493. /*===================== M A I N  C A L L I N G  R O U T I N E S ==============*/
  494. /*
  495.  * two sets of main routines
  496.  * if "DEBUG" is defined, you get a main routine that reads in one date,
  497.  * parses it, and prints the result
  498.  * if "DEBUG" is not defined, you get a routine that returns 1 if the current
  499.  * time is within the time range of the argument string, 0 if not
  500.  *
  501.  * "DEBUG" san be set to two levels; "1" gives you just the result (1 or 0),
  502.  * but you can use the print function "prtime()" to print out key times in
  503.  * the parse.  "2" gives you complete debugging info from YACC as well
  504.  */
  505.  
  506. #ifdef DEBUG
  507.  
  508. /*
  509.  * set the flag YYDEBUG
  510.  */
  511. #if DEBUG > 1
  512. #define YYDEBUG        /* flag so YACC will generate debugging info */
  513. extern int yydebug;    /* constant to tell YACC to generate debugging info */
  514. #endif
  515.  
  516. int linect = 0;        /* number of expression being tested */
  517. char *password;        /* password being tested */
  518.  
  519. /*
  520.  * main routine -- execute the given test and print the result
  521.  */
  522. main()
  523. {
  524.     char buf[BUFSIZ];        /* input buffer */
  525.     char pbuf[BUFSIZ];        /* buffer for password */
  526.     register char *p, *b;        /* used to load password */
  527.  
  528. #if DEBUG > 1
  529.     yydebug = 1;        /* YACC is to give full debugging output */
  530. #endif
  531.  
  532.     /*
  533.      * initialize the password to nothing
  534.      */
  535.     pbuf[0] = '\0';
  536.  
  537.     /*
  538.      * get the input; if EOF, quit
  539.      */
  540.     while(fgets(buf, BUFSIZ, stdin) != CH_NULL){
  541.         /*
  542.          * if it is a new password change the old one
  543.          */
  544.         if (buf[0] == 'p'){
  545.             for(b = &buf[1]; isspace(*b); b++)
  546.             p = pbuf;
  547.             while(*b && *b != '\n')
  548.                 *p++ = *b++;
  549.             *p = '\0';
  550.             PRINTF("new password is \"%s\"\n", pbuf);
  551.             password = pbuf;
  552.             initpw();
  553.             continue;
  554.         }
  555.  
  556.         /*
  557.          * if there is no password, warn
  558.          */
  559.         if (pbuf[0] == '\0'){
  560.             PRINTF("no password; say 'p <password>' to set one\n");
  561.             continue;
  562.         }
  563.  
  564.         /*
  565.          * new expression
  566.          */
  567.         linect++;
  568.  
  569.         /*
  570.          * print the buffer
  571.          */
  572.         PRINTF("buf is <%s>\n", buf);
  573.  
  574.         /*
  575.          * parse the date and process the result
  576.          */
  577.         (void) passtest(buf);
  578.     }
  579.  
  580.     /*
  581.      * no problem
  582.      */
  583.     exit(0);
  584. }
  585.  
  586. #endif
  587.